﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Mail;
using WebService4.MerchantService;

namespace WebService4
{
	public class GLKTestServiceImplementation : IGLKServiceImplementation
	{
		readonly List<Product> _products = new List<Product>
                       {
                           new Product {ID = 1, Name = "Product1", Price = 220},
                           new Product {ID = 2, Name = "Product2", Price = 540},
                           new Product {ID = 3, Name = "Product3", Price = 1100},
                           new Product {ID = 4, Name = "Product4", Price = 5000},
                       };
       private readonly Product _balance = new Product { ID = -5, Name = "Пополнение баланса", Price = 0 };

		#region IGLKServiceImplementation Members

		public Product GetBalanceProduct()
		{
			return _balance;
		}

		public IEnumerable<Product> GetProducts()
		{
			return _products;
		}

		public void UpdateOrderState(glk_Order order, registerOrderResult regResult)
		{
			using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
			{
				order.BankOrderID = regResult.orderId;
				db.glk_OrderStatus.InsertOnSubmit(new glk_OrderStatus
				{
					OrderID = order.ID,
					Status = (byte)OrderState.Registered,
					TimeStamp = DateTime.Now
				});
				db.SubmitChanges();
			}
		}

		public glk_Order CreateOrder(int userID, IEnumerable<Product> selectedProducts, out IList<Product> products)
		{
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
			{
				var order = new glk_Order { ClientID = userID };
				db.glk_Orders.InsertOnSubmit(order);
				db.SubmitChanges();
				products = selectedProducts as IList<Product> ?? selectedProducts.ToList();

				var glkProgucts =
					products.Select(x => new glk_OrderProduct { ProductID = x.ID, ProductPrice = x.Price, OrderID = order.ID });
				db.glk_OrderProducts.InsertAllOnSubmit(glkProgucts);
				db.SubmitChanges();
				return order;
			}
		}

		public int CreateClient(string email)
		{
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
			{
				if (db.glk_Clients.Any(x => x.Email.ToUpper() == email.ToUpper())) return 0;
				var client = new glk_Client { Email = email };
				db.glk_Clients.InsertOnSubmit(client);
				db.SubmitChanges();
				return client.ID;
			}
		}

		public int GetClientByEmail(string email)
		{
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
			{
				var client = db.glk_Clients.FirstOrDefault(x => x.Email.Trim().ToUpper() == email.Trim().ToUpper());
				return client == null ? 0 : client.ID;
			}
		}

        public OrderInfo CheckOrderState(string bankOrderID)
        {
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
            {
                var order = db.glk_Orders.FirstOrDefault(x => x.BankOrderID == bankOrderID);
                return order == null 
                    ? null 
                    : new OrderInfo { ID = order.ID, State = (OrderState)order.glk_OrderStatus.Max(x => x.Status), ClientEmail = order.glk_Client.Email};
            }
        }

        public OrderInfo GetOrderData(int orderID)
        {
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
            {
                var order = db.glk_Orders.SingleOrDefault(x => x.ID == orderID);
                if (order == null) return null;
                var selectedProducts = (order.glk_OrderProducts.Count == 1 &&
                                        order.glk_OrderProducts.First().ProductID == _balance.ID)
                                           ? new[] { new Product { ID = _balance.ID, Name = _balance.Name, Price = order.glk_OrderProducts.First().ProductPrice } }
                                           : _products.Where( x => order.glk_OrderProducts.Select(op => op.ProductID).Contains(x.ID)).ToArray();
                return new OrderInfo { Products = selectedProducts };
            }
        }

        public List<OrderInfo> GetConfirmedOrders()
        {
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
            {
                var orders = db.glk_Orders
                               .Where(x => x.glk_OrderStatus.Any(s => s.Status == (byte) OrderState.Confirmed))
                               .Select(order => new OrderInfo
                                   {
                                       ID = order.ID,
                                       Products = (order.glk_OrderProducts.Count == 1 &&
                                                   order.glk_OrderProducts.First().ProductID == _balance.ID)
                                                      ? new[]{new Product { ID = _balance.ID, Name = _balance.Name, Price = order.glk_OrderProducts.First().ProductPrice } }
                                                      : _products.Where(x => order.glk_OrderProducts.Select(op => op.ProductID).Contains(x.ID)).ToArray(),
                                       State = OrderState.Confirmed,
                                       ClientEmail = order.glk_Client.Email
                                   }).ToList();
                return orders;
            }
        }

        public void SavePaymentResult(orderStatusResponse bankResponse, ref OrderInfo orderInfo)
        {
            using (var db = new GLKDatabaseDataContext(Properties.Settings.Default.GLKConnectionString))
            {
                var orderID = int.Parse(bankResponse.orderNumber);

                var paymentResult = new glk_PaymentResult
                {
                    TimeStamp = DateTime.Now,
                    OrderStatus = bankResponse.orderStatus,
                    ErrorCode = bankResponse.errorCode,
                    ErrorMessage = bankResponse.errorMessage,
                    OrderNumber = bankResponse.orderNumber,
                    Pan = bankResponse.pan,
                    Expiration = bankResponse.expiration,
                    CardHolderName = bankResponse.cardholderName,
                    Amount = bankResponse.amount,
                    Currency = bankResponse.currency,
                    ApprovalCode = bankResponse.approvalCode,
                    AuthCode = bankResponse.authCode.ToString(CultureInfo.GetCultureInfo("ru")),
                    Ip = bankResponse.ip,
                    ClientID = bankResponse.clientId,
                    BindingID = bankResponse.bindingId
                };
                db.glk_PaymentResults.InsertOnSubmit(paymentResult);

                if (!db.glk_OrderStatus.Any(x => x.OrderID == orderID && x.Status == (byte)OrderState.SuccessReturned))
                {
                    db.glk_OrderStatus.InsertOnSubmit(new glk_OrderStatus
                    {
                        OrderID = orderID,
                        TimeStamp = DateTime.Now,
                        Status = (byte)OrderState.SuccessReturned
                    });
                }

                // если заказ подтвежден
                if (bankResponse.orderStatus == 2)
                {
                    // и в БД сервиса нет такой записи, внести ее
                    if (!db.glk_OrderStatus.Any(x => x.OrderID == orderID && x.Status == (byte) OrderState.Confirmed))
                    {
                        db.glk_OrderStatus.InsertOnSubmit(new glk_OrderStatus
                            {
                                OrderID = orderID,
                                TimeStamp = DateTime.Now,
                                Status = (byte) OrderState.Confirmed
                            });
                    }
                    orderInfo.State = OrderState.Confirmed;
                    orderInfo.Products = GetOrderData(orderID).Products;
                }
                else orderInfo.State = OrderState.Declined;

                db.SubmitChanges();
            }
        }
        
		public MailMessage GetMessage(string email, IEnumerable<Product> products)
		{
			const string @from = "glk_info@mail.ru";
			var to = email;
			const string subject = "ГЛК: Результаты платежа";
			var body = "Вы совершили полупку в магазине ГЛК\n ";
			body += "Вы оплатили следующие товары: \n";
			foreach (var product in products)
			{
				body += product.Name + " (" + product.Price + "руб.)\n";
			}
			var message = new MailMessage
			{
				From = new MailAddress(@from),
				Body = body,
				Subject = subject
			};
			message.To.Add(to);
			return message;
		}

		#endregion

	}
}